package modelo.escenario;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import modelo.carrera.Conductor;
import modelo.controles.Control;
import modelo.geometria.Figura;
import modelo.geometria.Grilla;
import modelo.geometria.Vector;
import modelo.obstaculos.Obstaculo;
import modelo.seniales.Semaforo;
import modelo.vehiculos.Vehiculo;

/**
 * Ciudad es un Singleton
 */
public class Ciudad {
	
	private GuiaT mapa;
	
	private Grilla<Obstaculo> grilla;
		
	private static Ciudad ciudad;
	
	static {
		ciudad = new Ciudad();
		ciudad.mapa = ConstructorEscenario.construirGuiaTEstandar();
		ciudad.grilla = ConstructorEscenario.construirElementosEnEscenarioEstandar();
	}
	
	private Ciudad()
	{
	}
	
	public static Ciudad getCiudad()
	{
		return ciudad;
	}
	
	public ArrayList<Vehiculo> obtenerVehiculosCercanos(Control control)
	{
		ArrayList<Vehiculo> transito = new ArrayList<Vehiculo>();
		
		for (Vehiculo vehiculo : getVehiculos()) {
			if ( vehiculo.getCuerpo().solapa(control.getVision()) )
				transito.add(vehiculo);
		}
		
		return transito;
	}

	public ArrayList<Obstaculo> obtenerObstaculosCercanos(Figura vision){
	//TODO mirar!
		ArrayList<Obstaculo> obstaculosCercanos = new ArrayList<Obstaculo>();
		
		for (Obstaculo obstaculo : getObstaculos()){
			if ( obstaculo.getCuerpo().solapa(vision))
				obstaculosCercanos.add(obstaculo);
		}
		return obstaculosCercanos;
	}

	public ArrayList<Obstaculo> getObstaculos(){

		ArrayList<Obstaculo> obstaculos = new ArrayList<Obstaculo>();
		Iterator<Vector> itr = grilla.iterator();
		while (itr.hasNext()){
			List<Obstaculo> elementos = grilla.get(itr.next());
			if (elementos != null){
				for (Obstaculo elemento : elementos){
					obstaculos.add(elemento);
				}	
			}
		}
		return obstaculos;
	}


	public ArrayList<Obstaculo> getObstaculos(Transitable lugar){

		ArrayList<Obstaculo> obstaculos = new ArrayList<Obstaculo>();
		Iterator<Vector> itr = grilla.iterator();
		while (itr.hasNext()){
			List<Obstaculo> elementos = grilla.get(itr.next());
			if (elementos != null){
				for (Obstaculo elemento : elementos){
					if (lugar.getSuperficie().solapa(elemento.getCuerpo()))
						obstaculos.add(elemento);
				}	
			}
		}
		return obstaculos;
	}	

	
	public ArrayList<Semaforo> getSemaforos(Transitable lugar){
		
		ArrayList<Semaforo> semaforos = new ArrayList<Semaforo>();
		Iterator<Obstaculo> itr = getObstaculos().iterator();
		while (itr.hasNext()){
				Obstaculo e = itr.next();
				if (e instanceof Semaforo && lugar.getSuperficie().solapa(e.getCuerpo()))
					semaforos.add((Semaforo) e);
		}
		return semaforos;
	}	
	
	
	
	public ArrayList<Control> getControles() {
		
		ArrayList<Control> controles = new ArrayList<Control>();
		Iterator<Obstaculo> itr = getObstaculos().iterator();
		while (itr.hasNext()){
				Obstaculo e = itr.next();
				if (e instanceof Control)
					controles.add((Control) e);
		}
		return controles;
	}
	
	public ArrayList<Vehiculo> getVehiculos() {
		ArrayList<Vehiculo> vehiculos = new ArrayList<Vehiculo>();
		Iterator<Obstaculo> itr = getObstaculos().iterator();
		while (itr.hasNext()){
				Obstaculo e = itr.next();
				if (e instanceof Vehiculo)
					vehiculos.add((Vehiculo) e);
		}
		return vehiculos;
	}

	public ArrayList<Semaforo> getSemaforos(){
		ArrayList<Semaforo> semaforos = new ArrayList<Semaforo>();
		Iterator<Obstaculo> itr = getObstaculos().iterator();
		while (itr.hasNext()){
				Obstaculo e = itr.next();
				if (e instanceof Semaforo)
					semaforos.add((Semaforo) e);
		}
		return semaforos;
	}
	
	public Cuadra getCuadra(Vector posicion){
	
		Iterable<Cuadra> cuadras = mapa.obtenerCuadras();
		for (Cuadra cuadra : cuadras) {
			if (cuadra.contienePosicion(posicion))
				return cuadra;
		}
		return null;
	}
	
	public Cruce getCruce(Vector posicion){
		
		Iterable<Cruce> cruces = mapa.obtenerCruces();
		for (Cruce cruce : cruces) {
			if (cruce.contienePosicion(posicion))
				return cruce;
		}
		return null;
	}
	
	public void addObstaculo(Obstaculo obstaculo){
		grilla.addElemento(obstaculo);
	}

	public GuiaT getGuiaT(){
		return mapa;
	}

	public Grilla<Obstaculo> getGrilla() {
		return grilla;
	}

	public Transitable getTransitable(Vector posicion) {
		Transitable transitable = getCruce(posicion);
		if (transitable == null) transitable = getCruce(posicion);
		return transitable;
	}
}
